# coding: utf-8

import logging
import urllib
from favshop.models import *
from favshop.ali import *
from favshop.utils import *
from favshop.constant import *
from django.http import HttpResponse, HttpResponseRedirect
from django.utils import simplejson
from django.shortcuts import render_to_response
from google.appengine.api import datastore_errors
from google.appengine.api import memcache
from google.appengine.api import users

logging.getLogger().setLevel(logging.INFO)

#-------------------------------------------------------------------------------
# Favshop UI View Part
#-------------------------------------------------------------------------------
def decrator_check_favshopuser(func):
    def new_func(*args, **kwargs):
        user = users.get_current_user()
        if user is None:
            return HttpResponseRedirect(users.create_login_url('/favshop/'))
        else:
            favshopuser = FavshopUser.get_by_key_name(
                MODEL_KEY_PREFIX+user.email())
            if favshopuser is None:
                return HttpResponseRedirect(users.create_login_url('/favshop/'))
        return func(*args, **kwargs)
    return new_func

@decrator_check_favshopuser
def default(request):
    context = {}
    context['log_out_url'] = users.create_logout_url('/favshop/')
    context['favshop_username'] = users.get_current_user().email()
    return render_to_response('main.html', context)

def about(request):
    context = {}
    context['favshop_username'] = users.get_current_user().email()
    return render_to_response('about.html', context)

def addfavshopuser(request):
    from django import forms
    class AddFavshopUserForm(forms.Form):
        username = forms.CharField(max_length=100)
    
    if request.method == 'POST':
        form = AddFavshopUserForm(request.POST)
        if form.is_valid(): # process adding favshopuser
            username = form.cleaned_data['username']
#            logging.info(type(username))
            u_entity = FavshopUser.get_by_key_name(MODEL_KEY_PREFIX+username)
            if u_entity is None:
                u_entity = FavshopUser(key_name=MODEL_KEY_PREFIX+username,
                    username=username, sub_list=[])
                u_entity.put()

    form = AddFavshopUserForm()

    return HttpResponse('''<form action="/favshop/adduser" method="POST">
        %s
        <input type="submit" value="Submit" />
        </form>
        ''' % form.as_p())
        
#-------------------------------------------------------------------------------
# Favshop AJAX API
#-------------------------------------------------------------------------------
# TODO: getuserinfo need unit test...
def getuserinfo(nickname):
    '''
    getuserinfo will get user information from DS or Ali-SIP. 
    Param:
        nickname - unicode  
    Return:
        UserInfo entity    
    '''
    user_info_entity = UserInfo.get_by_key_name(MODEL_KEY_PREFIX+nickname)
    if user_info_entity is None:
        user_info_sip = taobao_user_get(nick=nickname.encode('utf-8'),
            fields='nick,sex,buyer_credit,seller_credit,location.city,'\
            'location.state,location.country,created,last_visit'
        )
        if user_info_sip is None:
            return None
        else:
            resp = user_info_sip['rsp']
            entity = UserInfo(
                key_name=MODEL_KEY_PREFIX+resp['users'][0]['nick'],
                nick=resp['users'][0]['nick'],
                created=str2datetime(resp['users'][0]['created']),
                last_visit=str2datetime(resp['users'][0]['last_visit']),
                location_city=resp['users'][0]['location']['city'],
                location_state=resp['users'][0]['location']['state'],
                buyer_good_num=int(resp['users'][0]['buyer_credit']['good_num']),
                buyer_level=int(resp['users'][0]['buyer_credit']['level']),
                buyer_score=int(resp['users'][0]['buyer_credit']['score']),
                buyer_total_num=int(resp['users'][0]['buyer_credit']['total_num']),
                seller_good_num=int(resp['users'][0]['seller_credit']['good_num']),
                seller_level=int(resp['users'][0]['seller_credit']['level']),
                seller_score=int(resp['users'][0]['seller_credit']['score']),
                seller_total_num=int(resp['users'][0]['seller_credit']['total_num'])
            )
            entity.put()
            return entity
    else:
        if (datetime.timedelta(days=USER_UPDATE_INTERVAL) < 
                (datetime.datetime.now()-user_info_entity.last_update)):
            # user info out of date (over one day)
            user_info_sip = taobao_user_get(nick=nickname.encode('utf-8'),
                fields='nick,sex,buyer_credit,seller_credit,location.city,'\
                'location.state,location.country,created,last_visit'
            )
            if user_info_sip is not None:
                # update user info with the latest data
                user_info_entity.nick=user_info_sip['rsp']['users'][0]['nick']
                user_info_entity.created=str2datetime(user_info_sip['rsp']['users'][0]['created'])
                user_info_entity.last_visit=str2datetime(user_info_sip['rsp']['users'][0]['last_visit'])
                user_info_entity.location_city=user_info_sip['rsp']['users'][0]['location']['city']
                user_info_entity.location_state=user_info_sip['rsp']['users'][0]['location']['state']
                user_info_entity.buyer_good_num=int(user_info_sip['rsp']['users'][0]['buyer_credit']['good_num'])
                user_info_entity.buyer_level=int(user_info_sip['rsp']['users'][0]['buyer_credit']['level'])
                user_info_entity.buyer_score=int(user_info_sip['rsp']['users'][0]['buyer_credit']['score'])
                user_info_entity.buyer_total_num=int(user_info_sip['rsp']['users'][0]['buyer_credit']['total_num'])
                user_info_entity.seller_good_num=int(user_info_sip['rsp']['users'][0]['seller_credit']['good_num'])
                user_info_entity.seller_level=int(user_info_sip['rsp']['users'][0]['seller_credit']['level'])
                user_info_entity.seller_score=int(user_info_sip['rsp']['users'][0]['seller_credit']['score'])
                user_info_entity.seller_total_num=int(user_info_sip['rsp']['users'][0]['seller_credit']['total_num'])
                user_info_entity.put()
        return user_info_entity

# TODO: getshopinfo need unit test...
def getshopinfo(nickname):
    '''
    getshopinfo will get shop information from DS or Ali-SIP
    Param:
        nickname - unicode 
    Return:
        ShopInfo entity
    '''
    shop_info_entity = ShopInfo.get_by_key_name(MODEL_KEY_PREFIX+nickname)
    if shop_info_entity is None:
        shop_info_sip = taobao_shop_get(nick=nickname.encode('utf-8'),
            fields='sid,cid,nick,title,desc,bulletin,pic_path,create,modified'
        )
        if shop_info_sip is None:
            return None
        else:
            resp = shop_info_sip['rsp']
            si_entity = ShopInfo(
                key_name=MODEL_KEY_PREFIX+resp['shops'][0]['nick'])
            si_entity.sid = resp['shops'][0]['sid']
            si_entity.cid = resp['shops'][0]['cid']
            si_entity.nick = resp['shops'][0]['nick']
            si_entity.title = resp['shops'][0]['title']
            si_entity.desc = resp['shops'][0]['desc']
            si_entity.bulletin = resp['shops'][0]['bulletin']
            si_entity.pic_path = resp['shops'][0]['pic_path']
#            si_entity.create = str2datetime(resp['shops'][0]['create'])
            si_entity.modified = str2datetime(resp['shops'][0]['modified'])
            si_entity.put()
            return si_entity
    else:
        if (datetime.timedelta(days=SHOP_UPDATE_INTERVAL) < 
                (datetime.datetime.now()-shop_info_entity.last_update)):
            # shop info out of date (over one day)
            shop_info_sip = taobao_shop_get(nick=nickname.encode('utf-8'),
                fields='sid,cid,nick,title,desc,bulletin,pic_path,create,modified'
            )
            if shop_info_sip is not None:
                # update shop info with the latest data
                shop_info_entity.sid = shop_info_sip['rsp']['shops'][0]['sid']
                shop_info_entity.cid = shop_info_sip['rsp']['shops'][0]['cid']
                shop_info_entity.nick = shop_info_sip['rsp']['shops'][0]['nick']
                shop_info_entity.title = shop_info_sip['rsp']['shops'][0]['title']
                shop_info_entity.desc = shop_info_sip['rsp']['shops'][0]['desc']
                shop_info_entity.bulletin = shop_info_sip['rsp']['shops'][0]['bulletin']
                shop_info_entity.pic_path = shop_info_sip['rsp']['shops'][0]['pic_path']
#                shop_info_entity.create = str2datetime(shop_info_sip['rsp']['shops'][0]['create'])
                shop_info_entity.modified = str2datetime(shop_info_sip['rsp']['shops'][0]['modified'])
                shop_info_entity.put()
        return shop_info_entity
    
def getsubscriptioninfo(request, nickname):
    '''
    nickname - unicode
    '''
    subscription_info_entity = SubscriptionInfo.get_by_key_name(
        MODEL_KEY_PREFIX+nickname,
        parent=getcurrentupdating())
    if subscription_info_entity is not None:
        return HttpResponse(simplejson.dumps(
            subscriptioninfo2outputdict(subscription_info_entity),
            ensure_ascii=False))
    else:
        return HttpResponse('{}')

# TODO: need unit test
def subscribeshop(request):
    '''
    ajax API for subscription. 
    Param:
        shopnick, favshopuser
    Return:
        ERROR - Server error
        OK - User already subscribe this shop
        REFRESH - Clint need to refresh subscription side bar
        FULL - No more space for user subscription
    '''
    if request.method == 'POST':
        shopnick = request.POST['nick'].strip()
        favshopuser = request.POST['favshopuser'].strip()
        
        fu_entity = FavshopUser.get_by_key_name(MODEL_KEY_PREFIX+favshopuser)
        if fu_entity is not None:
            if shopnick in fu_entity.sub_list: 
                # favshop user already subscribe this shop
                return HttpResponse('OK')
            else:
                sub_entity = SubscriptionInfo.get_by_key_name(
                    MODEL_KEY_PREFIX+shopnick)
                if sub_entity is None:
                    # new shop, no subscription record
                    user_info = getuserinfo(shopnick)
                    shop_info = getshopinfo(shopnick)
                    if user_info is None or shop_info is None:
                        return HttpResponse('ERROR')
                    sub_entity = SubscriptionInfo(
                        key_name=MODEL_KEY_PREFIX+shopnick,
                        parent=getcurrentupdating(),
                        nick=shopnick)
                    sub_entity.put()

                if -1 == FAVSHOP_USER_MAX_SUBSCRIPTION or \
                    len(fu_entity.sub_list) < FAVSHOP_USER_MAX_SUBSCRIPTION:
                    fu_entity.sub_list.append(shopnick)
                    fu_entity.put()
                    return HttpResponse('REFRESH')
                else:
                    return HttpResponse('FULL')
    return HttpResponse('ERROR')

# TODO: need unit test
def unsubscribeshop(request):
    '''
    unsubscribe shop subscription
    Param:
        shopnick, favshopuser
    Return:
        ERROR - Server error.
        REFRESH - Delete OK, need to refresh side bar. 
    '''
    if request.method == 'POST':
        shopnick = request.POST['nick'].strip()
        favshopuser = request.POST['favshopuser'].strip()
        
        fu_entity = FavshopUser.get_by_key_name(MODEL_KEY_PREFIX+favshopuser)
        if fu_entity is not None:
            if shopnick in fu_entity.sub_list:
                fu_entity.sub_list.remove(shopnick)
                fu_entity.put()
                return HttpResponse('REFRESH')
    return HttpResponse('ERROR')

def getsidebar(request):
    '''
    get side bar JSON object
    '''
    ret_obj = None
    if request.method == 'POST':
        favshopuser = request.POST['favshopuser'].strip()
        fu_entity = FavshopUser.get_by_key_name(MODEL_KEY_PREFIX+favshopuser)
        if fu_entity is not None:
            key_list = [MODEL_KEY_PREFIX+m for m in fu_entity.sub_list]
            entity_list = ShopInfo.get_by_key_name(key_list)
            ret_obj = []
            for e in entity_list:
                ret_obj.append({'nick': e.nick,
                    'title': e.title,
                    'quoted_nick': urllib.quote(e.nick.encode('GB2312'))
                })
    return HttpResponse(simplejson.dumps(ret_obj, ensure_ascii=False))

def getmaincontent(request):
    '''
    get main content JSON object, including ShopInfo, UserInfo, SubscriptionInfo,
    SubUpdateLog, ChangeEvent
    '''
    ret_obj = None
    if request.method == 'POST':
        favshopuser = request.POST['favshopuser'].strip()
        shopnick = request.POST['nick'].strip()
        limit = int(request.POST['limit'])
        fu_entity = FavshopUser.get_by_key_name(MODEL_KEY_PREFIX+favshopuser)
        if fu_entity is not None:
            if shopnick in fu_entity.sub_list:
                ret_obj = {}
                si_entity = ShopInfo.get_by_key_name(MODEL_KEY_PREFIX+shopnick)
                ret_obj['shopinfo'] = shopinfo2outputdict(si_entity)
                ui_entity = UserInfo.get_by_key_name(MODEL_KEY_PREFIX+shopnick)
                ret_obj['userinfo'] = userinfo2outputdict(ui_entity)
                subi_entity = SubscriptionInfo.get_by_key_name(
                    MODEL_KEY_PREFIX+shopnick, 
                    parent=getcurrentupdating())
                ret_obj['subscriptioninfo'] = subscriptioninfo2outputdict(
                    subi_entity)
                ret_obj['changeevent'] = celist2outputlist(
                    fetch_changeevent(shopnick, limit, 0))
                ret_obj['limit'] = limit
                ret_obj['offset'] = 0
                ret_obj['nick'] = shopnick
                ret_obj['updatelog'] = ullist2outputlist(
                    fetch_updatelog(shopnick))
    return HttpResponse(simplejson.dumps(ret_obj, ensure_ascii=False))

def getchangeevent(request):
    '''
    request handler, AJAX API
    Param:
        nick, limit=10, offset=0
    Return:
        JSON string of 
    '''
    ret_obj = None
    if request.method == 'POST':
        ret_obj = {}
        shopnick = request.POST['nick'].strip()
        limit = int(request.POST['limit'])
        offset = int(request.POST['offset'])
        if offset<0: offset=0
        ret_obj['changeevent'] = celist2outputlist(
            fetch_changeevent(shopnick, limit, offset))
        ret_obj['nick'] = shopnick
        ret_obj['limit'] = limit
        ret_obj['offset'] = offset
    return HttpResponse(simplejson.dumps(ret_obj, ensure_ascii=False))

def fetch_changeevent(nick, limit=10, offset=0):
    '''
    internal function, fetch change event from DS
    Param:
        nick, limit, offset
    Return:
        object
    '''
    ret_obj = None
    q = ChangeEvent.all()
    q.filter('nick = ', nick).order('-timestamp')
    record_set = q.fetch(limit=limit, offset=offset)
    ret_obj = record_set
    return ret_obj

def fetch_updatelog(nick):
    '''
    fetch update log within 2 days
    Param:
        nick
    Retuen:
        object of update log
    '''
    ret_obj = None
    q = SubUpdateLog.all()
    q.filter('nick = ', nick)
    q.filter('update_timestamp > ', 
        datetime.datetime.now()-datetime.timedelta(days=2))
    q.order('-update_timestamp')
    ret_obj = []
    for item in q: ret_obj.append(item)
    return ret_obj
#-------------------------------------------------------------------------------
# test Alisoft API
#-------------------------------------------------------------------------------
# TODO: testvalidateuser need unit test
def testvalidateuser(request):
    output = alisoft_validateUser(userId=request.GET.get('user_id'),
        appInstanceId=request.GET.get('app_instance_id'),
        token=request.GET.get('token'))
    return HttpResponse(simplejson.dumps(output, ensure_ascii=False))

# TODO: testitemsget need unit test
def testitemsget(request):
    output = taobao_items_get(nicks=u'园园衣橱'.encode('utf-8'),
        page_no='1',
        page_size=str(ITEMS_GET_PAGE_SIZE),
        fields='iid,title,nick,type,cid,pic_path,delist_time,price,post_fee'
    )
    return HttpResponse(simplejson.dumps(output, ensure_ascii=False))

# TODO: testshopget need unit test
def testshopget(request):
    output = taobao_shop_get(nick=u'园园衣橱'.encode('utf-8'),
        fields='sid,cid,nick,title,desc,bulletin,pic_path,modified'
    )
    return HttpResponse(simplejson.dumps(output, ensure_ascii=False))

# TODO: testuserget need unit test 
def testuserget(request):
    output = taobao_user_get(nick=u'c5shop'.encode('utf-8'),
        fields='nick,sex,buyer_credit,seller_credit,location.city,location.state,location.country,created,last_visit'
    )
    return HttpResponse(simplejson.dumps(output, ensure_ascii=False))
